﻿using System;
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ.Client.Framing.Impl;
using WJ.Infrastructure.CQRS;
using WJ.Infrastructure.Serializer;

namespace WJ.Infrastructure.RabbitMQ
{
    public class MessageBus : IMessageBus
    {
        string exchangeName = "TestExchange";


        public void Dispose()
        {
            throw new NotImplementedException();
        }

        public bool Publish(IMessage message)
        {
            using (var conn = ConnManage.CreateConn())
            {
                using (var channel = conn.CreateModel())
                {
                    channel.ExchangeDeclare(exchangeName, "topic");

                    var body = message.SerializeBinary();

                    var properties = channel.CreateBasicProperties();

                    properties.Persistent = true;

                    string routeKey = exchangeName + "." + message.ToPic;
                    channel.BasicPublish(exchange: exchangeName,
                        routingKey: routeKey,
                        basicProperties: properties,
                        body: body);

                    return true;
                }
            }
        }

        public void Subscribe(Action<IMessage> handle, string[] toPic, string routeKey)
        {
            var conn = ConnManage.CreateConn();

            var channel = conn.CreateModel();

            channel.ExchangeDeclare(exchangeName, "topic");

            foreach (var item in toPic)
            {
                channel.QueueDeclare(queue: item,
                    durable: true,
                    exclusive: false,
                    autoDelete: false,
                    arguments: null);

                channel.QueueBind(item, exchangeName, exchangeName + "." + routeKey);
            }


            var consumer = new EventingBasicConsumer(channel);

            consumer.Received += (model, ea) =>
            {
                var body = ea.Body;

                IMessage message = body.DeserializeBinary() as IMessage;

                handle(message);

                channel.BasicAck(ea.DeliveryTag, false);
            };

            foreach (var item in toPic)
            {
                var consumerTag = channel.BasicConsume(queue: item,
                    noAck: false,
                    consumer: consumer);
            }
        }
    }
}